package org.cy.evolution.ioc.compiler.generator;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;

import org.cy.evolution.ioc.compiler.constant.EvolutionConstant;
import org.cy.evolution.ioc.compiler.utils.ClassUtil;

import javax.annotation.processing.Messager;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;

public class ComponentGenerator {
    /**
     * 日志工具类
     */
    private Messager messager;

    /**
     * 包名
     */
    private String packageName;

    /**
     * 生成的代理类名
     */
    private String proxyClassName;

    /**
     * 被注解修饰的类
     */
    private TypeElement classElement;

    public ComponentGenerator(Messager messager, Elements elements, TypeElement classElement) {
        this.messager = messager;
        packageName = ClassUtil.getPackageName(elements, classElement);
        this.classElement = classElement;
        String className = ClassUtil.getClassName(classElement, packageName);
        proxyClassName = className + EvolutionConstant.COMPONENT_GENERATE_SUFFIX;
    }

    public JavaFile generate() {
        TypeSpec componentClass = this.generateComponentClass(
                this.generateGetMethod(),
                this.generateBuilderClass(
                        this.generateBuildMethod()
                )
        );
        return JavaFile.builder(this.packageName, componentClass).build();
    }


    /**
     * 生成方法: build
     * public EvolutionComponent<T> build() {}
     * @return 方法对象
     */
    private MethodSpec generateBuildMethod() {
        return MethodSpec.methodBuilder("build")
                .addModifiers(Modifier.PUBLIC)
                .addAnnotation(Override.class)
                .returns(ParameterizedTypeName.get(EvolutionConstant.INTERFACE_COMPONENT, TypeName.get(classElement.asType())))
                .addStatement("return new $T()", ClassName.get(this.packageName, this.proxyClassName))
                .build();
    }

    /**
     * 生成内部类: Builder
     * public static class Builder extends EvolutionComponent.Builder<T> {}
     * @param buildMethod 实现的抽象方法: build
     * @return 内部类对象
     */
    private TypeSpec generateBuilderClass(MethodSpec buildMethod) {
        return TypeSpec.classBuilder("Builder")
                .addModifiers(Modifier.PUBLIC)
                .addModifiers(Modifier.STATIC)
                .superclass(ParameterizedTypeName.get(EvolutionConstant.ABSTRACT_COMPONENT_BUILDER,
                        ParameterizedTypeName.get(EvolutionConstant.INTERFACE_COMPONENT, TypeName.get(classElement.asType()))))
                .addMethod(buildMethod)
                .build();
    }

    /**
     * 生成方法：Get
     * public T get() {}
     * @return
     */
    private MethodSpec generateGetMethod() {
        return MethodSpec.methodBuilder("get")
                .addAnnotation(Override.class)
                .addModifiers(Modifier.PUBLIC)
                .returns(TypeName.get(this.classElement.asType()))
                .addStatement("return new $T()", ClassName.get(this.classElement))
                .build();
    }

    /**
     * 生成组件类
     * public class XXXComponent implements EvolutionComponent<XXX> {}
     * @return
     */
    private TypeSpec generateComponentClass(MethodSpec getMethod, TypeSpec innerClass) {
        return TypeSpec.classBuilder(this.proxyClassName)
                .addModifiers(Modifier.PUBLIC)
                .addSuperinterface(ParameterizedTypeName.get(EvolutionConstant.INTERFACE_COMPONENT, TypeName.get(this.classElement.asType())))
                .addMethod(MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE).build())
                .addMethod(getMethod)
                .addType(innerClass)
                .build();
    }
}
